package cn.zyg.ymcc.service.impl;

import cn.zyg.ymcc.constants.RedisSmsConstants;
import cn.zyg.ymcc.domain.MessageSms;
import cn.zyg.ymcc.dto.RedisSmsDto;
import cn.zyg.ymcc.dto.SmsCodeDto;
import cn.zyg.ymcc.enums.GlobalExceptionCode;
import cn.zyg.ymcc.properties.SmsRegisterProperties;
import cn.zyg.ymcc.service.IMessageSmsService;
import cn.zyg.ymcc.service.IVerifyCodeService;
import cn.zyg.ymcc.util.AssertUtil;
import cn.zyg.ymcc.util.StrUtils;
import cn.zyg.ymcc.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    @Autowired
    private IMessageSmsService messageSmsService;
    @Autowired
    private SmsRegisterProperties smsRegisterProperties;
    @Override
    public String imageCodeKey(String imageCodeKey) {
        // 工具类生产图形验证码
        String code = StrUtils.getComplexRandomString(4);
        // 注入RedisTemplate，保存,过期时间为5分钟
        redisTemplate.opsForValue().set(imageCodeKey,code,5, TimeUnit.MINUTES);
        // 使用工具类生成图形验证码编码之后的base64的字符串
        String base64Str = VerifyCodeUtils.verifyCode(110, 40, code);
        return base64Str;
    }
/**
    @Override
    public void sendSmsCode(String phone) {
        // 1.参数校验
        if (phone == null) {
            throw new GlobalCustomException(GlobalExceptionCode.ERROR);
        }
        // 2.图形验证码校验
        if (StringUtils.isEmpty(imageCode)) {
            throw new BusinessException("图片验证码不能为空！");
        }
        // 2. 校验图形验证码是否过期、正确
        Object o = redisTemplate.opsForValue().get(key);
            if (o == null) {
            throw  new BusinessException("图形验证码过期，请重新获取");
        }
            if (!o.toString().equalsIgnoreCase(imageCode)) {
            throw new BusinessException("图形验证码错误");
        }
        // 3.业务拼接键，去Redis中查询code
        String redisKey = "register:" + phone;
        Object obj = redisTemplate.opsForValue().get(redisKey);
        Date date = new Date();
        String code = "";
        if (obj != null) {
            // 1.获取到value的时间戳
            String[] split = obj.toString().split(":");
            Long time = Long.valueOf(split[1]);
            // 2.判断是否过了一分钟，如果没过，就提示用户操作频繁
            if (date.getTime() - time < 60000) {
                throw new GlobalCustomException(GlobalExceptionCode.OPERATING_FREQUENTLY_ERROR);
            }
            // 3.如果超过了一分钟，就用之前的code
            code = split[0];
        } else {
            // 如果不存在，就生成一个code
             code = StrUtils.getRandomString(6);
        }
        // 4.将code+time存到redis
        redisTemplate.opsForValue().set(redisKey,code+":"+date.getTime(),300*1000,TimeUnit.MILLISECONDS);
        // 5.存储消息发送日志
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle("注册验证码");
        messageSms.setContent("您的验证码为" + code + ",请在5分钟内使用");
        messageSms.setSendTime(date);
        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = request.getRemoteAddr();
        messageSms.setIp(ip);
        messageSmsService.insert(messageSms);
        // 6.发送短信验证码
        log.info("您的验证码为" + code + ",请在5分钟内使用");
    }
*/

    /**
     * 优化手机验证码注册代码
     * @param smsCodeDto
     */
    @Override
    public void sendSmsCode(SmsCodeDto smsCodeDto) {
        String imageCode = smsCodeDto.getImageCode();
        String imageCodeKey = smsCodeDto.getImageCodeKey();
        String phone = smsCodeDto.getPhone();
        // 1.参数校验
        AssertUtil.isPhone(phone,GlobalExceptionCode.PHONE_FORMAT_ERROR);

        // 2.图形验证码校验
        //  2.1. 校验图形验证码是否为空
        AssertUtil.isNotNull(imageCode,GlobalExceptionCode.IMAGECODE_IS_NOT_NULL);
        //  2.2. 校验图形验证码是否过期、正确
        Object o = redisTemplate.opsForValue().get(imageCodeKey);
        AssertUtil.isEqualsIgnoreCase((String) o,imageCode,GlobalExceptionCode.IMAGECODE_ERROR);
        // 3.业务拼接键，去Redis中查询code
        String redisKey = String.format(RedisSmsConstants.REDIS_REGISTER_PHONE_KEY,phone);
        Object obj = redisTemplate.opsForValue().get(redisKey);
        Date date = new Date();
        String code = "";
        if (obj != null) {
            // 1.获取到value的时间戳
            RedisSmsDto redisSmsDto = (RedisSmsDto)obj;
            // 2.判断是否过了一分钟，如果没过，就提示用户操作频繁
            boolean boo = (date.getTime() - redisSmsDto.getTime() < smsRegisterProperties.getInterval());
            AssertUtil.isFalse(boo,GlobalExceptionCode.OPERATING_FREQUENTLY_ERROR);
            // 3.如果超过了一分钟，就用之前的code
            code = redisSmsDto.getCode();
        } else {
            // 如果不存在，就生成一个code
            code = StrUtils.getRandomString(smsRegisterProperties.getCodesize());
        }
        // 4.将code+time存到redis
        RedisSmsDto redisSmsDto = new RedisSmsDto();
        redisTemplate.opsForValue().set(redisKey,redisSmsDto,smsRegisterProperties.getExpiredtime(),TimeUnit.MILLISECONDS);
        sendMessage(date, code);
    }

    /**
     * 在一个方法中如果代码过多，那么我们一定要把相同业务逻辑的代码进行抽取，抽成一个新的方法，在原有方法中进行调用
     * @param date
     * @param code
     */
    private void sendMessage(Date date, String code) {
        // 5.存储消息发送日志
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle(smsRegisterProperties.getTitle());
        String content = String.format(smsRegisterProperties.getContent(), code);
        messageSms.setContent(content);
        messageSms.setSendTime(date);
        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = request.getRemoteAddr();
        messageSms.setIp(ip);
        messageSmsService.insert(messageSms);
        // 6.发送短信验证码
        log.info(content);
    }


}
